home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / ADVANCED / projshadow.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  8.9 KB  |  378 lines

  1.  
  2. /* projshadow.c - by Tom McReynolds, SGI */
  3.  
  4. /* Rendering shadows using projective shadows. */
  5.  
  6. #include <GL/glut.h>
  7. #include <stdlib.h>
  8.  
  9. /* Create a single component texture map */
  10. GLfloat *
  11. make_texture(int maxs, int maxt)
  12. {
  13.   int s, t;
  14.   static GLfloat *texture;
  15.  
  16.   texture = (GLfloat *) malloc(maxs * maxt * sizeof(GLfloat));
  17.   for (t = 0; t < maxt; t++) {
  18.     for (s = 0; s < maxs; s++) {
  19.       texture[s + maxs * t] = ((s >> 4) & 0x1) ^ ((t >> 4) & 0x1);
  20.     }
  21.   }
  22.   return texture;
  23. }
  24.  
  25. enum {
  26.   SPHERE = 1, CONE, LIGHT, LEFTWALL, FLOOR
  27. };
  28.  
  29. enum {
  30.   X, Y, Z, W
  31. };
  32. enum {
  33.   A, B, C, D
  34. };
  35.  
  36. /* create a matrix that will project the desired shadow */
  37. void
  38. shadowmatrix(GLfloat shadowMat[4][4],
  39.   GLfloat groundplane[4],
  40.   GLfloat lightpos[4])
  41. {
  42.   GLfloat dot;
  43.  
  44.   /* find dot product between light position vector and ground plane normal */
  45.   dot = groundplane[X] * lightpos[X] +
  46.     groundplane[Y] * lightpos[Y] +
  47.     groundplane[Z] * lightpos[Z] +
  48.     groundplane[W] * lightpos[W];
  49.  
  50.   shadowMat[0][0] = dot - lightpos[X] * groundplane[X];
  51.   shadowMat[1][0] = 0.f - lightpos[X] * groundplane[Y];
  52.   shadowMat[2][0] = 0.f - lightpos[X] * groundplane[Z];
  53.   shadowMat[3][0] = 0.f - lightpos[X] * groundplane[W];
  54.  
  55.   shadowMat[X][1] = 0.f - lightpos[Y] * groundplane[X];
  56.   shadowMat[1][1] = dot - lightpos[Y] * groundplane[Y];
  57.   shadowMat[2][1] = 0.f - lightpos[Y] * groundplane[Z];
  58.   shadowMat[3][1] = 0.f - lightpos[Y] * groundplane[W];
  59.  
  60.   shadowMat[X][2] = 0.f - lightpos[Z] * groundplane[X];
  61.   shadowMat[1][2] = 0.f - lightpos[Z] * groundplane[Y];
  62.   shadowMat[2][2] = dot - lightpos[Z] * groundplane[Z];
  63.   shadowMat[3][2] = 0.f - lightpos[Z] * groundplane[W];
  64.  
  65.   shadowMat[X][3] = 0.f - lightpos[W] * groundplane[X];
  66.   shadowMat[1][3] = 0.f - lightpos[W] * groundplane[Y];
  67.   shadowMat[2][3] = 0.f - lightpos[W] * groundplane[Z];
  68.   shadowMat[3][3] = dot - lightpos[W] * groundplane[W];
  69.  
  70. }
  71.  
  72. /* find the plane equation given 3 points */
  73. void
  74. findplane(GLfloat plane[4],
  75.   GLfloat v0[3], GLfloat v1[3], GLfloat v2[3])
  76. {
  77.   GLfloat vec0[3], vec1[3];
  78.  
  79.   /* need 2 vectors to find cross product */
  80.   vec0[X] = v1[X] - v0[X];
  81.   vec0[Y] = v1[Y] - v0[Y];
  82.   vec0[Z] = v1[Z] - v0[Z];
  83.  
  84.   vec1[X] = v2[X] - v0[X];
  85.   vec1[Y] = v2[Y] - v0[Y];
  86.   vec1[Z] = v2[Z] - v0[Z];
  87.  
  88.   /* find cross product to get A, B, and C of plane equation */
  89.   plane[A] = vec0[Y] * vec1[Z] - vec0[Z] * vec1[Y];
  90.   plane[B] = -(vec0[X] * vec1[Z] - vec0[Z] * vec1[X]);
  91.   plane[C] = vec0[X] * vec1[Y] - vec0[Y] * vec1[X];
  92.  
  93.   plane[D] = -(plane[A] * v0[X] + plane[B] * v0[Y] + plane[C] * v0[Z]);
  94. }
  95.  
  96. void 
  97. sphere(void)
  98. {
  99.   glPushMatrix();
  100.   glTranslatef(60.f, -50.f, -360.f);
  101.   glCallList(SPHERE);
  102.   glPopMatrix();
  103. }
  104.  
  105. void 
  106. cone(void)
  107. {
  108.   glPushMatrix();
  109.   glTranslatef(-40.f, -40.f, -400.f);
  110.   glCallList(CONE);
  111.   glPopMatrix();
  112.  
  113. }
  114.  
  115. enum {
  116.   NONE, SHADOW
  117. };
  118.  
  119. int rendermode = NONE;
  120.  
  121. void
  122. menu(int mode)
  123. {
  124.   rendermode = mode;
  125.   glutPostRedisplay();
  126. }
  127.  
  128. GLfloat leftwallshadow[4][4];
  129. GLfloat floorshadow[4][4];
  130.  
  131. GLfloat lightpos[] =
  132. {50.f, 50.f, -320.f, 1.f};
  133.  
  134. void
  135. redraw(void)
  136. {
  137.   /* material properties for objects in scene */
  138.   static GLfloat wall_mat[] =
  139.   {1.f, 1.f, 1.f, 1.f};
  140.   static GLfloat sphere_mat[] =
  141.   {1.f, .5f, 0.f, 1.f};
  142.   static GLfloat cone_mat[] =
  143.   {0.f, .5f, 1.f, 1.f};
  144.  
  145.   glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  146.  
  147.   /* Note: wall verticies are ordered so they are all front facing this lets
  148.      me do back face culling to speed things up.  */
  149.  
  150.   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, wall_mat);
  151.  
  152.   /* floor */
  153.   /* make the floor textured */
  154.   glEnable(GL_TEXTURE_2D);
  155.  
  156.   /* Since we want to turn texturing on for floor only, we have to make floor 
  157.      a separate glBegin()/glEnd() sequence. You can't turn texturing on and
  158.      off between begin and end calls */
  159.   glBegin(GL_QUADS);
  160.   glNormal3f(0.f, 1.f, 0.f);
  161.   glTexCoord2i(0, 0);
  162.   glVertex3f(-100.f, -100.f, -320.f);
  163.   glTexCoord2i(1, 0);
  164.   glVertex3f(100.f, -100.f, -320.f);
  165.   glTexCoord2i(1, 1);
  166.   glVertex3f(100.f, -100.f, -520.f);
  167.   glTexCoord2i(0, 1);
  168.   glVertex3f(-100.f, -100.f, -520.f);
  169.   glEnd();
  170.  
  171.   glDisable(GL_TEXTURE_2D);
  172.  
  173.   if (rendermode == SHADOW) {
  174.     glDisable(GL_DEPTH_TEST);
  175.     glDisable(GL_LIGHTING);
  176.     glColor3f(0.f, 0.f, 0.f);  /* shadow color */
  177.  
  178.     glPushMatrix();
  179.     glMultMatrixf((GLfloat *) floorshadow);
  180.     cone();
  181.     glPopMatrix();
  182.  
  183.     glPushMatrix();
  184.     glMultMatrixf((GLfloat *) floorshadow);
  185.     sphere();
  186.     glPopMatrix();
  187.     glEnable(GL_DEPTH_TEST);
  188.     glEnable(GL_LIGHTING);
  189.   }
  190.   /* walls */
  191.  
  192.   if (rendermode == SHADOW) {
  193.     glEnable(GL_STENCIL_TEST);
  194.     glStencilFunc(GL_ALWAYS, 1, 0);
  195.     glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  196.   }
  197.   glBegin(GL_QUADS);
  198.   /* left wall */
  199.   glNormal3f(1.f, 0.f, 0.f);
  200.   glVertex3f(-100.f, -100.f, -320.f);
  201.   glVertex3f(-100.f, -100.f, -520.f);
  202.   glVertex3f(-100.f, 100.f, -520.f);
  203.   glVertex3f(-100.f, 100.f, -320.f);
  204.   glEnd();
  205.  
  206.   if (rendermode == SHADOW) {
  207.     glStencilFunc(GL_EQUAL, 1, 1);
  208.     glDisable(GL_DEPTH_TEST);
  209.     glDisable(GL_LIGHTING);
  210.     glColor3f(0.f, 0.f, 0.f);  /* shadow color */
  211.     glDisable(GL_DEPTH_TEST);
  212.     glPushMatrix();
  213.     glMultMatrixf((GLfloat *) leftwallshadow);
  214.     cone();
  215.     glPopMatrix();
  216.     glEnable(GL_DEPTH_TEST);
  217.     glDisable(GL_STENCIL_TEST);
  218.     glEnable(GL_DEPTH_TEST);
  219.     glEnable(GL_LIGHTING);
  220.   }
  221.   glBegin(GL_QUADS);
  222.   /* right wall */
  223.   glNormal3f(-1.f, 0.f, 0.f);
  224.   glVertex3f(100.f, -100.f, -320.f);
  225.   glVertex3f(100.f, 100.f, -320.f);
  226.   glVertex3f(100.f, 100.f, -520.f);
  227.   glVertex3f(100.f, -100.f, -520.f);
  228.  
  229.   /* ceiling */
  230.   glNormal3f(0.f, -1.f, 0.f);
  231.   glVertex3f(-100.f, 100.f, -320.f);
  232.   glVertex3f(-100.f, 100.f, -520.f);
  233.   glVertex3f(100.f, 100.f, -520.f);
  234.   glVertex3f(100.f, 100.f, -320.f);
  235.  
  236.   /* back wall */
  237.   glNormal3f(0.f, 0.f, 1.f);
  238.   glVertex3f(-100.f, -100.f, -520.f);
  239.   glVertex3f(100.f, -100.f, -520.f);
  240.   glVertex3f(100.f, 100.f, -520.f);
  241.   glVertex3f(-100.f, 100.f, -520.f);
  242.   glEnd();
  243.  
  244.   glPushMatrix();
  245.   glTranslatef(lightpos[X], lightpos[Y], lightpos[Z]);
  246.   glDisable(GL_LIGHTING);
  247.   glColor3f(1.f, 1.f, .7f);
  248.   glCallList(LIGHT);
  249.   glEnable(GL_LIGHTING);
  250.   glPopMatrix();
  251.  
  252.   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cone_mat);
  253.   cone();
  254.  
  255.   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, sphere_mat);
  256.   sphere();
  257.  
  258.   glutSwapBuffers();    /* high end machines may need this */
  259. }
  260.  
  261. /* ARGSUSED1 */
  262. void 
  263. key(unsigned char key, int x, int y)
  264. {
  265.   if (key == '\033')
  266.     exit(0);
  267. }
  268.  
  269. const int TEXDIM = 256;
  270. /* Parse arguments, and set up interface between OpenGL and window system */
  271.  
  272. int
  273. main(int argc, char *argv[])
  274. {
  275.   GLfloat *tex;
  276.   GLUquadricObj *sphere, *cone, *base;
  277.   GLfloat plane[4];
  278.   GLfloat v0[3], v1[3], v2[3];
  279.  
  280.   glutInit(&argc, argv);
  281.   glutInitWindowSize(512, 512);
  282.   glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL | GLUT_DOUBLE);
  283.   (void) glutCreateWindow("projection shadows");
  284.   glutDisplayFunc(redraw);
  285.   glutKeyboardFunc(key);
  286.  
  287.   glutCreateMenu(menu);
  288.   glutAddMenuEntry("No Shadows", NONE);
  289.   glutAddMenuEntry("Shadows", SHADOW);
  290.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  291.  
  292.   /* draw a perspective scene */
  293.   glMatrixMode(GL_PROJECTION);
  294.   glFrustum(-100., 100., -100., 100., 320., 640.);
  295.   glMatrixMode(GL_MODELVIEW);
  296.  
  297.   /* turn on features */
  298.   glEnable(GL_DEPTH_TEST);
  299.   glEnable(GL_LIGHTING);
  300.   glEnable(GL_LIGHT0);
  301.  
  302.   /* make shadow matricies */
  303.  
  304.   /* 3 points on floor */
  305.   v0[X] = -100.f;
  306.   v0[Y] = -100.f;
  307.   v0[Z] = -320.f;
  308.   v1[X] = 100.f;
  309.   v1[Y] = -100.f;
  310.   v1[Z] = -320.f;
  311.   v2[X] = 100.f;
  312.   v2[Y] = -100.f;
  313.   v2[Z] = -520.f;
  314.  
  315.   findplane(plane, v0, v1, v2);
  316.   shadowmatrix(floorshadow, plane, lightpos);
  317.  
  318.   /* 3 points on left wall */
  319.   v0[X] = -100.f;
  320.   v0[Y] = -100.f;
  321.   v0[Z] = -320.f;
  322.   v1[X] = -100.f;
  323.   v1[Y] = -100.f;
  324.   v1[Z] = -520.f;
  325.   v2[X] = -100.f;
  326.   v2[Y] = 100.f;
  327.   v2[Z] = -520.f;
  328.  
  329.   findplane(plane, v0, v1, v2);
  330.   shadowmatrix(leftwallshadow, plane, lightpos);
  331.  
  332.   /* place light 0 in the right place */
  333.   glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
  334.  
  335.   /* remove back faces to speed things up */
  336.   glCullFace(GL_BACK);
  337.  
  338.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  339.  
  340.   /* make display lists for sphere and cone; for efficiency */
  341.  
  342.   glNewList(SPHERE, GL_COMPILE);
  343.   sphere = gluNewQuadric();
  344.   gluSphere(sphere, 20.f, 20, 20);
  345.   gluDeleteQuadric(sphere);
  346.   glEndList();
  347.  
  348.   glNewList(LIGHT, GL_COMPILE);
  349.   sphere = gluNewQuadric();
  350.   gluSphere(sphere, 5.f, 20, 20);
  351.   gluDeleteQuadric(sphere);
  352.   glEndList();
  353.  
  354.   glNewList(CONE, GL_COMPILE);
  355.   cone = gluNewQuadric();
  356.   base = gluNewQuadric();
  357.   glRotatef(-90.f, 1.f, 0.f, 0.f);
  358.   gluDisk(base, 0., 20., 20, 1);
  359.   gluCylinder(cone, 20., 0., 60., 20, 20);
  360.   gluDeleteQuadric(cone);
  361.   gluDeleteQuadric(base);
  362.   glEndList();
  363.  
  364.   glNewList(FLOOR, GL_COMPILE);
  365.   glEndList();
  366.  
  367.   glNewList(LEFTWALL, GL_COMPILE);
  368.   glEndList();
  369.  
  370.   /* load pattern for current 2d texture */
  371.   tex = make_texture(TEXDIM, TEXDIM);
  372.   glTexImage2D(GL_TEXTURE_2D, 0, 1, TEXDIM, TEXDIM, 0, GL_RED, GL_FLOAT, tex);
  373.   free(tex);
  374.  
  375.   glutMainLoop();
  376.   return 0;             /* ANSI C requires main to return int. */
  377. }
  378.